package cz.proks.schoolpupilbook.gwt.widget.common;

import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;

import com.google.gwt.cell.client.ButtonCell;
import com.google.gwt.cell.client.DateCell;
import com.google.gwt.cell.client.EditTextCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.SelectionCell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DecoratedPopupPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.SingleSelectionModel;

import cz.proks.schoolpupilbook.gwt.core.CookieHelper;
import cz.proks.schoolpupilbook.gwt.core.ResultNotifiable;
import cz.proks.schoolpupilbook.gwt.core.SchoolPupilBookFactory;
import cz.proks.schoolpupilbook.gwt.service.CourseService;
import cz.proks.schoolpupilbook.gwt.service.ListService;
import cz.proks.schoolpupilbook.gwt.service.ServiceFactory;
import cz.proks.schoolpupilbook.gwt.service.UserService;
import cz.proks.schoolpupilbook.shared.Constants;
import cz.proks.schoolpupilbook.shared.domain.Course;
import cz.proks.schoolpupilbook.shared.domain.Mark;
import cz.proks.schoolpupilbook.shared.domain.MarkComment;
import cz.proks.schoolpupilbook.shared.domain.User;
import cz.proks.schoolpupilbook.shared.domain.User.Role;
import cz.proks.schoolpupilbook.shared.domain.UserCourseRelation;
import cz.proks.schoolpupilbook.shared.domain.UserRelation;

public class LectorView extends Composite {
	interface LectorViewUiBinder extends UiBinder<Widget, LectorView> {
	}
	
	private static LectorViewUiBinder uiBinder = GWT.create(LectorViewUiBinder.class);

	@UiField TabLayoutPanel tabPanel;
	
	@UiField Button newUserButton;
	@UiField CellTable<User> userCellTable;
	
	@UiField Button newCourseButton;
	@UiField CellTable<Course> courseCellTable;
	
	@UiField Button newMarkButton;
	@UiField CellTable<Mark> markCellTable;
	
	@UiField Button newUserRelationButton;
	@UiField CellTable<UserRelation> userRelationCellTable;
	
	@UiField Button newUserCourseButton;
	@UiField CellTable<UserCourseRelation> userCourseRelationCellTable;
	
	private SingleSelectionModel<User> userSelectionModel;	
	private ListHandler<User> userHandler;
	private RefreshableAsyncDataProvider<User> userDataProvider;
	
	private SingleSelectionModel<Course> courseSelectionModel;	
	private ListHandler<Course> courseHandler;
	private RefreshableAsyncDataProvider<Course> courseDataProvider;
	
	private SingleSelectionModel<Mark> markSelectionModel;	
	private ListHandler<Mark> markHandler;
	private RefreshableAsyncDataProvider<Mark> markDataProvider;
	
	private SingleSelectionModel<UserRelation> userRelationSelectionModel;	
	private ListHandler<UserRelation> userRelationHandler;
	private RefreshableAsyncDataProvider<UserRelation> userRelationDataProvider;
	
	private SingleSelectionModel<UserCourseRelation> userCourseRelationSelectionModel;	
	private ListHandler<UserCourseRelation> userCourseRelationHandler;
	private RefreshableAsyncDataProvider<UserCourseRelation> userCourseRelationDataProvider;
	
	private TabSelectionHandler tabSelectionHandler;

	public LectorView() {		
		initWidget(uiBinder.createAndBindUi(this));
		tabSelectionHandler = new TabSelectionHandler();
		
		tabPanel.addSelectionHandler(tabSelectionHandler);
		
		initButtons();
		initUserCellTable();
		initCourseCellTable();
		initMarkCellTable();
		initUserRelationCellTable();
		initUserCourseRelationCellTable();	
	}
	
	private void initButtons() {
		newUserButton.addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event) {
				History.newItem(Constants.History.USER_NEW);	
			}
		});
		
		newCourseButton.addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event) {
				History.newItem(Constants.History.COURSE_NEW);				
			}
		});
		newMarkButton.addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event) {
				History.newItem(Constants.History.MARK_NEW);				
			}
		});
		newUserRelationButton.addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event) {
				History.newItem(Constants.History.USER_RELATION_NEW);			
			}
		});
		newUserCourseButton.addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event) {
				History.newItem(Constants.History.USER_COURSE_RELATION_NEW);
			}
		});
	}
	
	private void initUserCellTable() {		
		userSelectionModel = new SingleSelectionModel<User>();
		userHandler = new ListHandler<User>(new LinkedList<User>());
		userDataProvider = new UserDataProvider();
		
		Column<User, String> nameColumn = new UserColumn.NameColumn();
		Column<User, String> surnameColumn = new UserColumn.SurnameColumn();
		Column<User, String> roleColumn = new UserColumn.RoleColumn();
		Column<User, String> loginColumn = new UserColumn.LoginColumn();
		Column<User, String> passwordColumn = new UserColumn.PasswordColumn();
				
		userCellTable.addColumn(nameColumn, "Name");
		userCellTable.addColumn(surnameColumn, "Surname");
		userCellTable.addColumn(roleColumn, "Role");
		userCellTable.addColumn(loginColumn, "Login");
		userCellTable.addColumn(passwordColumn, "Password");
		
		userCellTable.setSelectionModel(userSelectionModel);
		userCellTable.addColumnSortHandler(userHandler);
		userDataProvider.addDataDisplay(userCellTable);
		
		userHandler.setComparator(nameColumn, new Comparator<User>() {			
			@Override
			public int compare(User o1, User o2) {
				return o1.getName().compareToIgnoreCase(o2.getName());
			}
		});
		userHandler.setComparator(surnameColumn, new Comparator<User>() {
			@Override
			public int compare(User o1, User o2) {
				return o1.getSurname().compareToIgnoreCase(o2.getSurname());
			}
		});
		userHandler.setComparator(roleColumn, new Comparator<User>() {
			@Override
			public int compare(User o1, User o2) {
				return o1.getRole().toString().compareToIgnoreCase(o2.getRole().toString());
			}
		});
		userHandler.setComparator(loginColumn, new Comparator<User>() {
			@Override
			public int compare(User o1, User o2) {
				return o1.getUsername().compareToIgnoreCase(o2.getUsername());
			}
		});			
	}
	
	private void initCourseCellTable() {
		courseSelectionModel = new SingleSelectionModel<Course>();
		courseHandler = new ListHandler<Course>(new LinkedList<Course>());
		courseDataProvider = new CourseDataProvider();
		
		Column<Course, String> codeColumn = new CourseColumn.CodeColumn();
		Column<Course, String> nameColumn = new CourseColumn.NameColumn();
		
		courseCellTable.addColumn(codeColumn, "Code");
		courseCellTable.addColumn(nameColumn, "Name");
		
		courseCellTable.setSelectionModel(courseSelectionModel);
		courseCellTable.addColumnSortHandler(courseHandler);
		courseDataProvider.addDataDisplay(courseCellTable);
		
		courseHandler.setComparator(codeColumn, new Comparator<Course>() {
			@Override
			public int compare(Course o1, Course o2) {
				return o1.getCode().compareToIgnoreCase(o2.getCode());
			}
		});
		courseHandler.setComparator(nameColumn, new Comparator<Course>() {
			@Override
			public int compare(Course o1, Course o2) {
				return o1.getName().compareToIgnoreCase(o2.getName());
			}
		});
	}
	
	private void initMarkCellTable() {
		markSelectionModel = new SingleSelectionModel<Mark>();
		markHandler = new ListHandler<Mark>(new LinkedList<Mark>());
		markDataProvider = new MarkDataProvider();
		
		Column<Mark, Date> timeColumn = new MarkColumn.TimeColumn();
		Column<Mark, String> courseColumn = new MarkColumn.CourseColumn();
		Column<Mark, String> lectorColumn = new MarkColumn.LectorColumn();
		Column<Mark, String> studentColumn = new MarkColumn.StudentColumn();
		Column<Mark, String> markColumn = new MarkColumn.MarkValueColumn();
		Column<Mark, String> commentColumn = new MarkColumn.CommentColumn();		
		
		markCellTable.addColumn(timeColumn, "Created");
		markCellTable.addColumn(courseColumn, "Course");
		markCellTable.addColumn(lectorColumn, "Lector");
		markCellTable.addColumn(studentColumn, "Student");
		markCellTable.addColumn(markColumn, "Mark");
		markCellTable.addColumn(commentColumn, "Comments");
		
		markCellTable.setSelectionModel(markSelectionModel);
		markCellTable.addColumnSortHandler(markHandler);
		markDataProvider.addDataDisplay(markCellTable);
		
		markHandler.setComparator(timeColumn, new Comparator<Mark>() {
			@Override
			public int compare(Mark o1, Mark o2) {
				return -1 * o1.getTime().compareTo(o2.getTime());
			}
		});
		markHandler.setComparator(courseColumn, new Comparator<Mark>() {
			@Override
			public int compare(Mark o1, Mark o2) {
				return o1.getCourse().getCode().compareToIgnoreCase(o2.getCourse().getCode());
			}
		});
		markHandler.setComparator(lectorColumn, new Comparator<Mark>() {
			@Override
			public int compare(Mark o1, Mark o2) {
				return o1.getLector().getFullName().compareToIgnoreCase(o2.getLector().getFullName());
			}
		});
		markHandler.setComparator(studentColumn, new Comparator<Mark>() {
			@Override
			public int compare(Mark o1, Mark o2) {
				return o1.getStudent().getFullName().compareToIgnoreCase(o2.getStudent().getFullName());
			}
		});
		markHandler.setComparator(markColumn, new Comparator<Mark>() {
			@Override
			public int compare(Mark o1, Mark o2) {
				return o1.getMark().compareToIgnoreCase(o2.getMark());
			}
		});
	}
	
	private void initUserRelationCellTable() {
		userRelationSelectionModel = new SingleSelectionModel<UserRelation>();
		userRelationHandler = new ListHandler<UserRelation>(new LinkedList<UserRelation>());
		userRelationDataProvider = new UserRelationDataProvider();
		
		Column<UserRelation, String> parentColumn = new UserRelationColumn.ParentColumn();
		Column<UserRelation, String> studentColumn = new UserRelationColumn.StudentColumn();
		
		userRelationCellTable.addColumn(parentColumn, "Parent");
		userRelationCellTable.addColumn(studentColumn, "Student");
		
		userRelationCellTable.setSelectionModel(userRelationSelectionModel);
		userRelationCellTable.addColumnSortHandler(userRelationHandler);
		userRelationDataProvider.addDataDisplay(userRelationCellTable);
		
		userRelationHandler.setComparator(parentColumn, new Comparator<UserRelation>() {
			@Override
			public int compare(UserRelation o1, UserRelation o2) {
				return o1.getParent().getFullName().compareToIgnoreCase(o2.getParent().getFullName());
			}
		});
		userRelationHandler.setComparator(studentColumn, new Comparator<UserRelation>() {
			@Override
			public int compare(UserRelation o1, UserRelation o2) {
				return o1.getStudent().getFullName().compareToIgnoreCase(o2.getStudent().getFullName());
			}
		});
	}
	
	private void initUserCourseRelationCellTable() {
		userCourseRelationSelectionModel = new SingleSelectionModel<UserCourseRelation>();
		userCourseRelationHandler = new ListHandler<UserCourseRelation>(new LinkedList<UserCourseRelation>());
		userCourseRelationDataProvider = new UserCourseRelationDataProvider();
		
		Column<UserCourseRelation, String> courseColumn = new UserCourseRelationColumn.CourseColumn();
		Column<UserCourseRelation, String> studentColumn = new UserCourseRelationColumn.StudentColumn();
		
		userCourseRelationCellTable.addColumn(courseColumn, "Course");
		userCourseRelationCellTable.addColumn(studentColumn, "Student");
		
		userCourseRelationCellTable.setSelectionModel(userCourseRelationSelectionModel);
		userCourseRelationCellTable.addColumnSortHandler(userCourseRelationHandler);
		userCourseRelationDataProvider.addDataDisplay(userCourseRelationCellTable);
		
		userCourseRelationHandler.setComparator(courseColumn, new Comparator<UserCourseRelation>() {
			@Override
			public int compare(UserCourseRelation o1, UserCourseRelation o2) {
				return o1.getCourse().getCode().compareToIgnoreCase(o2.getCourse().getCode());
			}
		});
		userCourseRelationHandler.setComparator(studentColumn, new Comparator<UserCourseRelation>() {
			@Override
			public int compare(UserCourseRelation o1, UserCourseRelation o2) {
				return o1.getUser().getFullName().compareToIgnoreCase(o2.getUser().getFullName());
			}
		});		
	}
	 
	private static class TabSelectionHandler implements SelectionHandler<Integer> {
		@Override
		public void onSelection(SelectionEvent<Integer> event) {
			// TODO Auto-generated method stub
			
		}
	}
	
	private static class UserColumn {		
		
		private static class NameColumn extends Column<User, String> {						
			public NameColumn() {
				super(new EditTextCell());
				setSortable(true);
				setFieldUpdater(new FieldUpdater<User, String>() {
					@Override
					public void update(int index, final User object, final String value) {
						if (!object.getName().equals(value)) {							
							object.setName(value);
							updateUser(object);
						}
					}					
				});
			}
			
			@Override
			public String getValue(User object) {
				return object.getName();
			}			
		}
		
		private static class SurnameColumn extends Column<User, String> {						
			public SurnameColumn() {
				super(new EditTextCell());
				setSortable(true);
				setFieldUpdater(new FieldUpdater<User, String>() {
					@Override
					public void update(int index, final User object, final String value) {
						if (!object.getSurname().equals(value)) {							
							object.setSurname(value);
							updateUser(object);									
						}
					}					
				});
			}
			
			@Override
			public String getValue(User object) {
				return object.getSurname();
			}			
		}
		
		private static class RoleColumn extends Column<User, String> {						
			public RoleColumn() {
				super(new SelectionCell(User.Role.asStringList()));
				setSortable(true);
				setFieldUpdater(new FieldUpdater<User, String>() {
					@Override
					public void update(int index, final User object, final String value) {
						Role role = Role.valueOf(value);
						if (object.getRole() != role) {							
							object.setRole(role);
							updateUser(object);
						}
					}					
				});
			}
			
			@Override
			public String getValue(User object) {
				return object.getRole().toString();
			}			
		}
		
		private static class LoginColumn extends Column<User, String> {						
			public LoginColumn() {
				super(new EditTextCell());
				setSortable(true);
				setFieldUpdater(new FieldUpdater<User, String>() {
					@Override
					public void update(int index, final User object, final String value) {
						if (!object.getUsername().equals(value)) {
							object.setUsername(value);
							updateUser(object);							
						}
					}					
				});
			}
			
			@Override
			public String getValue(User object) {
				return object.getUsername();
			}			
		}
		
		private static class PasswordColumn extends Column<User, String> {						
			public PasswordColumn() {
				super(new EditTextCell());
				setSortable(false);
				setFieldUpdater(new FieldUpdater<User, String>() {
					@Override
					public void update(int index, final User object, final String value) {
						if (!object.getPassword().equals(value)) {
							object.setPassword(value);
							updateUser(object);
						}
					}					
				});
			}
			
			@Override
			public String getValue(User object) {
				return object.getPassword();
			}			
		}
		
		private static void updateUser(final User user) {
			UserService userService = ServiceFactory.getUserService();			
			userService.save(user, new ResultNotifiable<Void>() {
				@Override
				public void onSucces(Void object) {	}

				@Override
				public void onError(Throwable t) {
					Window.alert("Communication failed: " + t.getLocalizedMessage());
				}
				
			});					
		}
		
	}

	private static class CourseColumn {
		private static class CodeColumn extends Column<Course, String> {
			public CodeColumn() {
				super(new EditTextCell());
				setSortable(true);
				setFieldUpdater(new FieldUpdater<Course, String>() {
					@Override
					public void update(int index, Course object, String value) {
						if (!object.getCode().equals(value)) {
							object.setCode(value);
							updateCourse(object);
						}
					}					
				});
			}
			
			@Override
			public String getValue(Course object) {
				return object.getCode();
			}
		}
		
		private static class NameColumn extends Column<Course, String> {
			public NameColumn() {
				super(new EditTextCell());
				setSortable(true);
				setFieldUpdater(new FieldUpdater<Course, String>() {
					@Override
					public void update(int index, Course object, String value) {
						if (!object.getName().equals(value)) {
							object.setName(value);
							updateCourse(object);
						}
					}					
				});
			}
			
			@Override
			public String getValue(Course object) {
				return object.getName();
			}
		}
		
		private static void updateCourse(final Course course) {
			CourseService courseService = ServiceFactory.getCourseService();
			courseService.save(course, new ResultNotifiable<Void>() {

				@Override
				public void onSucces(Void object) {	}

				@Override
				public void onError(Throwable t) {
					Window.alert("Communication failed: " + t.getLocalizedMessage());
				}				
			});
		}
	}
	
	private static class MarkColumn {
		private static class TimeColumn extends Column<Mark, Date> {
			public TimeColumn() {
				super(new DateCell());	
				setSortable(true);
			}
			
			@Override
			public Date getValue(Mark object) {
				return object.getTime();
			}
		}
		
		private static class CourseColumn extends Column<Mark, String> {
			public CourseColumn() {
				super(new TextCell());
				setSortable(true);
			}
			
			@Override
			public String getValue(Mark object) {
				return object.getCourse().getCode();
			}
		}
		
		private static class LectorColumn extends Column<Mark, String> {
			public LectorColumn() {
				super(new TextCell());
				setSortable(true);
			}
			
			@Override
			public String getValue(Mark object) {
				return object.getLector().getFullName();
			}
		}
		
		private static class StudentColumn extends Column<Mark, String> {
			public StudentColumn() {
				super(new TextCell());
				setSortable(true);
			}
			
			@Override
			public String getValue(Mark object) {
				return object.getStudent().getFullName();
			}
		}
		
		private static class MarkValueColumn extends Column<Mark, String> {
			public MarkValueColumn() {
				super(new TextCell());
				setSortable(true);
			}
			
			@Override
			public String getValue(Mark object) {
				return object.getMark();
			}
		}
		
		private static class CommentColumn extends Column<Mark, String> {			
			public CommentColumn() {				
				super(new ButtonCell());		
				setFieldUpdater(new FieldUpdater<Mark, String>() {
					
					@Override
					public void update(int index, Mark object, String value) {
						new CommentPopupPanel(object).center();
					}
				});
			}
			
			@Override
			public String getValue(Mark object) {
				return "Show comments";
			}
		}
	}
	
	private static class UserRelationColumn {
		private static class ParentColumn extends Column<UserRelation, String> {
			public ParentColumn() {
				super(new TextCell());
				setSortable(true);
			}
			
			@Override
			public String getValue(UserRelation object) {
				return object.getParent().getFullName();
			}
		}		
		
		private static class StudentColumn extends Column<UserRelation, String> {
			public StudentColumn() {
				super(new TextCell());
				setSortable(true);
			}
			
			@Override
			public String getValue(UserRelation object) {
				return object.getStudent().getFullName();
			}
		}		
	}
	
	private static class UserCourseRelationColumn {		
		private static class CourseColumn extends Column<UserCourseRelation, String> {
			public CourseColumn() {
				super(new TextCell());
				setSortable(true);
			}
			
			@Override
			public String getValue(UserCourseRelation object) {
				return object.getCourse().getCode();
			}
		}
		
		private static class StudentColumn extends Column<UserCourseRelation, String> {
			public StudentColumn() {
				super(new TextCell());
				setSortable(true);
			}
			
			@Override
			public String getValue(UserCourseRelation object) {
				return object.getUser().getFullName();
			}
		}
	}
	
	private static abstract class RefreshableAsyncDataProvider<T> extends AsyncDataProvider<T> {
		public void refresh() {
			onRangeChanged(null);
		}
	}

	private static class UserDataProvider extends RefreshableAsyncDataProvider<User> {						
		@Override
		protected void onRangeChanged(HasData<User> display) {
			ListService listService = ServiceFactory.getListService();
			listService.listUsers(new ResultNotifiable<LinkedList<User>>() {

				@Override
				public void onSucces(LinkedList<User> object) {
					updateRowData(0, object);
					updateRowCount(object.size(), true);
				}

				@Override
				public void onError(Throwable t) {
					Window.alert("Communication failed: " + t.getLocalizedMessage());
				}
				
			});
		}
	}
	
	private static class CourseDataProvider extends RefreshableAsyncDataProvider<Course> {
		@Override
		protected void onRangeChanged(HasData<Course> display) {
			ListService listService = ServiceFactory.getListService();
			listService.listCourses(new ResultNotifiable<LinkedList<Course>>() {				
				@Override
				public void onSucces(LinkedList<Course> object) {
					updateRowData(0, object);
					updateRowCount(object.size(), true);					
				}
				
				@Override
				public void onError(Throwable t) {
					Window.alert("Communication failed: " + t.getLocalizedMessage());
				}
			});						
		}
	}
	
	private static class MarkDataProvider extends RefreshableAsyncDataProvider<Mark> {
		@Override
		protected void onRangeChanged(HasData<Mark> display) {
			ListService listService = ServiceFactory.getListService();
			listService.listMarks(new ResultNotifiable<LinkedList<Mark>>() {

				@Override
				public void onSucces(LinkedList<Mark> object) {
					updateRowData(0, object);
					updateRowCount(object.size(), true);
				}

				@Override
				public void onError(Throwable t) {
					Window.alert("Communication failed: " + t.getLocalizedMessage());
				}				
			});				
		}
	}
	
	private static class UserRelationDataProvider extends RefreshableAsyncDataProvider<UserRelation> {
		@Override
		protected void onRangeChanged(HasData<UserRelation> display) {
			ListService listService = ServiceFactory.getListService();
			listService.listUserRelation(new ResultNotifiable<LinkedList<UserRelation>>() {

				@Override
				public void onSucces(LinkedList<UserRelation> object) {
					updateRowData(0, object);
					updateRowCount(object.size(), true);
				}

				@Override
				public void onError(Throwable t) {
					Window.alert("Communication failed: " + t.getLocalizedMessage());
				}				
			});					
		}
	}
	
	private static class UserCourseRelationDataProvider extends RefreshableAsyncDataProvider<UserCourseRelation> {
		@Override
		protected void onRangeChanged(HasData<UserCourseRelation> display) {
			ListService listService = ServiceFactory.getListService();
			listService.listUserCourseRelation(new ResultNotifiable<LinkedList<UserCourseRelation>>() {

				@Override
				public void onSucces(LinkedList<UserCourseRelation> object) {
					updateRowData(0, object);
					updateRowCount(object.size(), true);
				}

				@Override
				public void onError(Throwable t) {
					Window.alert("Communication failed: " + t.getLocalizedMessage());
				}				
			});						
		}
	}
	
	public static class CommentPopupPanel extends DecoratedPopupPanel {
		private final DateTimeFormat timeFormater = DateTimeFormat.getFormat("dd.MM.yyyy HH:mm");
		private final Mark mark;		
		
		public CommentPopupPanel(Mark mark) {
			super(true);
			this.mark = mark;			
						
			init();
		}
		
		private void init() {			
			addStyleName("rounded-corners");
			
			VerticalPanel panel = new VerticalPanel();			
			HorizontalPanel hPanel = new HorizontalPanel();
			
			final Label comment = new Label("Add your comment here:");
			final TextArea textArea = new TextArea();
			final Button backButton = new Button("Back");
			final Button submitButton = new Button("Submit");
			
			backButton.addStyleName("button");
			backButton.addStyleName("green");
			
			submitButton.addStyleName("button");
			submitButton.addStyleName("green");
			
			
			hPanel.add(backButton);
			hPanel.add(submitButton);
			hPanel.setSpacing(5);
			
			appendComments(panel);
			
			panel.add(comment);
			panel.add(textArea);
			panel.add(hPanel);			
			
			backButton.addClickHandler(new ClickHandler() {				
				@Override
				public void onClick(ClickEvent event) {					
					closePopup();
				}
			});
			
			submitButton.addClickHandler(new ClickHandler() {				
				@Override
				public void onClick(ClickEvent event) {
					 User user = CookieHelper.getLoggedUser();
					 
					 CommentSubmitEvent submitEvent = new CommentSubmitEvent(mark, user, textArea.getText());
					 SchoolPupilBookFactory.getEventBus().fireEvent(submitEvent);
					 
					 mark.addComment(user, new Date(), textArea.getText());					 
					 closePopup();
				}
			});
			
			setWidget(panel);
		}
		
		private void appendComments(VerticalPanel panel) {
			if (mark.getComments() != null) {
							
				for (MarkComment comment : mark.getComments()) {
					SafeHtmlBuilder sb = new SafeHtmlBuilder();
					Grid grid = new Grid(2,1);
					
					sb.appendHtmlConstant("<b>");
					sb.appendEscaped("At " + timeFormater.format(comment.getTime()) + " by " + comment.getContributor().getFullName());
					sb.appendHtmlConstant("</b>");
					
					grid.setWidget(0, 0, new HTML(sb.toSafeHtml()));
					
					sb = new SafeHtmlBuilder();
					sb.appendEscapedLines(comment.getComment());
					
					grid.setWidget(1, 0, new HTML(sb.toSafeHtml()));
					
					grid.setWidth("100%");
					grid.addStyleName("comment");
					
					panel.add(grid);
				}
			}
		}
		
		private void closePopup() {
			this.hide(true);
		}
	}
	
	public static class CommentSubmitEvent extends GwtEvent<CommentSubmitEvent.CommentSubmitHandler> {
		public interface CommentSubmitHandler extends EventHandler {
			void onNewComment(CommentSubmitEvent event);
		}
		
		public static Type<CommentSubmitHandler> TYPE = new Type<CommentSubmitEvent.CommentSubmitHandler>();
		
		private Mark mark;
		private User user;
		private String comment;
		
		public CommentSubmitEvent(Mark mark, User user, String comment) {
			super();
			this.mark = mark;
			this.user = user;
			this.comment = comment;
		}

		@Override
		public Type<CommentSubmitHandler> getAssociatedType() {
			return TYPE;
		}

		@Override
		protected void dispatch(CommentSubmitHandler handler) {
			handler.onNewComment(this);
		}

		public Mark getMark() {
			return mark;
		}				
		
		public User getUser() {
			return user;
		}

		public String getComment() {
			return comment;
		}
	}
}
